using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Principal;
using System.Web.Mvc;
using System.Web.Security;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.SimpleRegistration;
using DotNetOpenAuth.OpenId.RelyingParty;
using MvcCms.Data;
using MvcCms.Service;
using MvcCms.Service.Cache;
using MvcCms.Service.Code;
using MvcCms.Service.Code.Email;
using MvcCms.Service.Code.Membership;
using MvcCms.Service.Filters;
using MvcCms.Web.ViewModels;

namespace MvcCms.Web.Controllers
{
    [HandleError]
    public class AccountController : Service.Code.BaseClasses.CMSControllerBase
    {
        #region Constructors
        private readonly IAccountService _accountService;
        private readonly IMiscService _miscService;
        private readonly Portal _currentPortal;
        private readonly string _sitename;
        private readonly IFormsAuthentication _formsAuth;
        public AccountController(ICmsService cmsService, IZoneService zoneService, ICacheService cacheService, IFormsAuthentication formsAuth, IAccountService accountService, IMiscService miscService)
            : base(cmsService, zoneService, accountService)
        {
            _formsAuth = formsAuth;
            _accountService = accountService;
            _miscService = miscService;
            _currentPortal = cacheService.GetCurrentPortal();
            _sitename = _currentPortal.DisplayName;
        }
        #endregion

        private string GetResource(string resourcetype)
        {
            var portalresources = _currentPortal.PortalResources;
            PortalResource portalresource = portalresources.Where(resource => resource.ResourceName.Equals(resourcetype)).FirstOrDefault();
            if (portalresource != null)
            {
                return portalresource.Body;
            }
            else
            {
                return string.Empty;
            }
        }

        #region UserMethods
        //[RequireSsl(Redirect = true)]
        public ActionResult LogOn()
        {
            if (Request.IsAuthenticated) { return RedirectToAction("Index", "Home"); }
            ViewData["resourcebody"] = GetResource("Login");
            ViewData["referer"] = Request.UrlReferrer != null ? Request.UrlReferrer.ToString() : "";
            ViewData["SiteName"] = _sitename;
            ViewData["OpenId"] = "";
            ViewData["PageTitle"] = "Login";
            ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
            return View();
        }

        //[RequireSsl(Redirect = true)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult LogOn(string userName, string password, bool rememberMe, string returnUrl)
        {
            ViewData["resourcebody"] = GetResource("Login");
            ViewData["referer"] = returnUrl;
            ViewData["OpenId"] = "";
            ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
            if (!ValidateLogOn(userName, password))
            {
                if (ModelState.ContainsKey("ADMINPASSWORDCHANGE")) { TempData["ADMINPASSWORDCHANGE"] = true; Session["APC_UserName"] = userName; Session["APC_Guid"] = Guid.NewGuid(); return RedirectToAction("ChangePassword"); }
                ViewData["SiteName"] = _sitename;
                ViewData["PageTitle"] = "Login";
                return View();
            }
            if (Session["OpenId"] != null)
            {
                var user = _accountService.GetUser(userName);
                user.OpenId = Session["OpenId"].ToString();
                _accountService.EditUser(user);
                Session["OpenId"] = null;
            }
            _formsAuth.SignIn(userName, rememberMe);
            if ((!String.IsNullOrEmpty(returnUrl)) && (!returnUrl.Contains("account")))
            {
                return Redirect(returnUrl);
            }
            return RedirectToAction("Index", "Home");
        }

        public ActionResult LogOff()
        {
            _formsAuth.SignOut();

            return RedirectToAction("Index", "Home");
        }

        //[RequireSsl(Redirect = true)]
        public ActionResult Register()
        {
            var noBotKey = Guid.NewGuid();
            Session["noBotKey"] = noBotKey.ToString();
            ViewData["noBotKey"] = noBotKey.ToString();

            ViewData["resourcebody"] = GetResource("Register");
            ViewData["OpenId"] = "";
            ViewData["message"] = "";
            ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
            if (Request.UrlReferrer != null)
            {
                ViewData["referer"] = Request.UrlReferrer.ToString();
            }
            else
            {
                ViewData["referer"] = _currentPortal.URLAuthority;
            }
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Register";
            ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength;

            return View();
        }

        //[RequireSsl(Redirect = true)]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Register(string userName, string email, string password, string confirmPassword, string returnUrl, string noBotKey)
        {
            if (noBotKey == Session["noBotKey"].ToString())
            {
                ViewData["referer"] = returnUrl;
                ViewData["OpenId"] = "";
                ViewData["message"] = "";
                ViewData["resourcebody"] = "";
                ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
                ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength;
                if (Session["OpenId"] != null)
                {
                    MembershipCreateStatus createStatus;
                    Membership.CreateUser(userName, password, email, null, null, true, null, out createStatus);

                    if (createStatus == MembershipCreateStatus.Success)
                    {
                        _formsAuth.SignIn(userName, false /* createPersistentCookie */);
                        Roles.AddUserToRole(userName, "User");
                        User userToWelcome = _accountService.GetUser(userName);
                        userToWelcome.OpenId = Session["OpenId"].ToString();
                        _accountService.EditUser(userToWelcome);
                        MvcCmsEmails.Welcome(userToWelcome);
                        Session["OpenId"] = null;
                        return RedirectToAction("UserProfile", "Account", new { returnUrl });
                    }
                    ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus));
                }
                else
                {
                    if (ValidateRegistration(userName, email, password, confirmPassword))
                    {
                        // Attempt to register the user
                        MembershipCreateStatus createStatus;
                        Membership.CreateUser(userName, password, email, null, null, true, null, out createStatus);

                        if (createStatus == MembershipCreateStatus.Success)
                        {
                            _formsAuth.SignIn(userName, false);

                            Roles.AddUserToRole(userName, "User");

                            User userToWelcome = _accountService.GetUser(userName);
                            MvcCmsEmails.Welcome(userToWelcome);
                            return RedirectToAction("UserProfile", "Account", new { returnUrl });
                        }
                        ModelState.AddModelError("_FORM", ErrorCodeToString(createStatus));
                    }
                }
                // If we got this far, something failed, redisplay form

                ViewData["SiteName"] = _sitename;
                ViewData["PageTitle"] = "Register";
                ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength;
                return View();
            }
            else
            {
                return Redirect("http://" + _currentPortal.URLAuthority);
            }
        }

        [Authorize]
        public ActionResult UserProfile(string secretquestion, string secretanswer, string firstName, string lastName,
                                        string genderType, DateTime? birthDate, string occupation, string website,
                                        int? languageId, string country, string subscriptionType, string street,
                                        string city, string state, string zipcode, int? stateprovinceId, string title,
                                        string cell, string returnURL, string email)
        {
            ViewData["resourcebody"] = GetResource("Profile");
            var requestReferer = Request == null ? Request.UrlReferrer.ToString() : "";
            ViewData["returnUrl"] = !string.IsNullOrEmpty(returnURL) ? returnURL : requestReferer;
            ViewData["previouspage"] = "";
            string id = HttpContext.User.Identity.Name;

            User userToEdit = _accountService.GetUser(id);
            Profile profileToEdit = _accountService.GetProfile(userToEdit.UserID);
            if (languageId != null)
            {
                if (birthDate != null)
                {
                }
                if (profileToEdit == null)
                {
                    profileToEdit = new Profile { User = userToEdit };
                }

                profileToEdit.Subscription = subscriptionType;
                profileToEdit.Language = _miscService.GetLanguage(languageId.GetValueOrDefault());
                profileToEdit.Title = title;
                profileToEdit.FirstName = firstName;
                profileToEdit.LastName = lastName;
                profileToEdit.Gender = genderType.Trim();
                profileToEdit.BirthDate = birthDate.ToString() != "" ? birthDate.ToString() : null;
                profileToEdit.Occupation = occupation;
                profileToEdit.Website = website;
                profileToEdit.Street = street;
                profileToEdit.City = city;
                profileToEdit.StateProvince = _miscService.GetStateProvince(stateprovinceId.GetValueOrDefault());
                profileToEdit.ZipCode = zipcode;
                profileToEdit.Cell = cell;
                profileToEdit.LastModified = DateTime.Now;

                if (!_accountService.SetProfileData(profileToEdit))
                {
                    ModelState.AddModelError("", "There was a problem saving your profile.");
                }

                userToEdit.PasswordQuestion = secretquestion;
                userToEdit.PasswordAnswer = secretanswer;
                _accountService.EditUser(userToEdit);

                userToEdit.Email = email;
                _accountService.EditUser(userToEdit);

                ModelState.AddModelError("", "User Profile Updated");
                ViewData["previouspage"] = "Return to where you were";
            }

            var subscriptionList = new List<SelectListItem>
                                       {
                                           new SelectListItem {Value = "HTML", Text = "Subscribe to HTML Version"},
                                           new SelectListItem
                                               {Value = "Plain", Text = "Subscribe to Plain Text Version"},
                                           new SelectListItem {Value = "None", Text = "No Thanks"}
                                       };
            var genderList = new List<SelectListItem>
                                 {
                                     new SelectListItem {Value = "M", Text = "Male"},
                                     new SelectListItem {Value = "F", Text = "Female"}
                                 };
            IEnumerable<StateProvince> stateprovinceList = _miscService.ListStates();
            IEnumerable<Language> languages = _miscService.ListLanguages();


            string langid, stateid;
            if (profileToEdit != null)
            {
                langid = (profileToEdit.Language != null ? profileToEdit.Language.LanguageID.ToString() : "1");
                stateid = (profileToEdit.StateProvince != null ? profileToEdit.StateProvince.StateProvinceID.ToString() : "1");
            }
            else
            {
                langid = "1";
                stateid = "1";
            }

            ViewData["subscriptionType"] = new SelectList(subscriptionList, "Value", "Text", profileToEdit != null ? profileToEdit.Subscription.Trim() : "HTML");

            ViewData["languageid"] = new SelectList(languages, "LanguageID", "LanguageName", langid);

            ViewData["title"] = profileToEdit != null ? profileToEdit.Title : "";
            ViewData["firstName"] = profileToEdit != null ? profileToEdit.FirstName : "";
            ViewData["lastName"] = profileToEdit != null ? profileToEdit.LastName : "";

            ViewData["genderType"] = new SelectList(genderList, "Value", "Text", profileToEdit != null ? profileToEdit.Gender.Trim() : "M");

            ViewData["birthDate"] = profileToEdit != null ? profileToEdit.BirthDate : "";
            ViewData["occupation"] = profileToEdit != null ? profileToEdit.Occupation : "";
            ViewData["Website"] = profileToEdit != null ? profileToEdit.Website : "";
            ViewData["street"] = profileToEdit != null ? profileToEdit.Street : "";
            ViewData["city"] = profileToEdit != null ? profileToEdit.City : "";
            ViewData["StateProvinceID"] = new SelectList(stateprovinceList, "StateProvinceID", "Name", stateid);
            ViewData["ZipCode"] = profileToEdit != null ? profileToEdit.ZipCode : "";
            ViewData["cell"] = profileToEdit != null ? profileToEdit.Cell : "";

            ViewData["Email"] = userToEdit.Email;

            ViewData["PasswordQuestion"] = userToEdit.PasswordQuestion;
            ViewData["PasswordAnswer"] = userToEdit.PasswordAnswer;

            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Update Profile";

            return View();
        }

        //[RequireSsl(Redirect = true)]
        public ActionResult ChangePassword()
        {
            if (TempData["ADMINPASSWORDCHANGE"] != null) { ModelState.AddModelError("ADMINPASSWORDCHANGE", "You need to update your password since it was changed."); }
            else if (TempData["EMAILPASSWORDCHANGE"] != null) { ModelState.AddModelError("EMAILPASSWORDCHANGE", "Please enter your new password to continue on the site."); }
            else if (Membership.GetUser() == null) { RedirectToAction("Login"); }
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Change Password";
            ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength;

            var isEmailReset = TempData["EMAILPASSWORDCHANGE"] != null;
            ViewBag.IsEmailReset = isEmailReset;
            Session["IsEmailReset"] = isEmailReset;

            ViewBag.IsValid = true;
            return View();
        }

        [AcceptVerbs(HttpVerbs.Post)]
        //[RequireSsl(Redirect = true)]
        public ActionResult ChangePassword(string currentPassword, string newPassword, string confirmPassword, string changePwdGuid)
        {
            var myProvider = (WindsorMembershipProvider)Membership.Provider;
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Change Password";
            ViewData["PasswordLength"] = Membership.MinRequiredPasswordLength;

            var isASystemRequestedReset = false;
            var user = Membership.GetUser();

            bool isEmailReset = false;
            if (Session["IsEmailReset"] != null)
            {
                isEmailReset = bool.Parse(Session["IsEmailReset"].ToString());
            }
            ViewBag.IsEmailReset = isEmailReset;

            if (!string.IsNullOrEmpty(changePwdGuid))
            {
                if (Session["APC_Guid"] != null && Session["APC_Guid"].ToString() == changePwdGuid)
                {
                    user = Membership.GetUser(Session["APC_UserName"].ToString());
                    if (user != null && myProvider.ValidateUserIgnoreIsApproved(user.UserName, currentPassword))
                    {
                        //sign them in for now but set a flag in case their new password is bad
                        _formsAuth.SignIn(user.UserName, false);
                        isASystemRequestedReset = true;
                    }
                }
                if (Session["EPC_Guid"] != null && Session["EPC_Guid"].ToString() == changePwdGuid)
                {
                    user = Membership.GetUser(Session["EPC_UserName"].ToString());
                    if (!ValidateChangePassword(newPassword, confirmPassword))
                    {
                        ViewBag.IsValid = false;
                        return View();
                    }
                    if (myProvider.ChangePasswordFromEmail(user.UserName, newPassword))
                    {
                        //the desired action has been taken, restore the account
                        user.IsApproved = true;
                        Membership.UpdateUser(user);
                        return RedirectToAction("ChangePasswordSuccess");
                    }
                    else
                    {
                        ViewBag.IsValid = false;
                        ModelState.AddModelError("_FORM", "There was a problem saving your new password, please try again or contact " + _currentPortal.AdminEmail + ".");
                        return View();
                    }
                }
                else { RedirectToAction("LogOn"); }
            }
            else if (user == null) { RedirectToAction("LogOn"); }

            if (!ValidateChangePassword(currentPassword, newPassword, confirmPassword))
            {
                if (isASystemRequestedReset) { _formsAuth.SignOut(); }
                ViewBag.IsValid = false;
                return View();
            }

            try
            {
                if (!isASystemRequestedReset)
                {
                    if (myProvider.ChangePassword(user.UserName, currentPassword, newPassword))
                    {
                        return RedirectToAction("ChangePasswordSuccess");
                    }
                }
                else
                {
                    if (myProvider.ChangePasswordIgnoreIsApproved(user.UserName, currentPassword, newPassword))
                    {
                        //the desired action has been taken, restore the account
                        user.IsApproved = true;
                        Membership.UpdateUser(user);
                        return RedirectToAction("ChangePasswordSuccess");
                    }
                }
                if (isASystemRequestedReset) { _formsAuth.SignOut(); }
                ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                ViewBag.IsValid = false;
                return View();
            }
            catch (Exception ex)
            {
                if (isASystemRequestedReset) { _formsAuth.SignOut(); }

                if (ex.Message.StartsWith("Password must"))
                {
                    ModelState.AddModelError("_FORM", ex.Message);
                }
                else
                {
                    ModelState.AddModelError("_FORM", "The current password is incorrect or the new password is invalid.");
                }

                ViewBag.IsValid = false;
                return View();
            }
        }

        public ActionResult ChangePasswordSuccess()
        {
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Change Password";
            return View();
        }

        //[RequireSsl(Redirect = true)]
        public ActionResult ResetPassword()
        {
            ViewBag.Title = _sitename + " - " + "Reset Password";
            var model = new AccountModel
            {
                _Portal = _currentPortal
            };

            return View(model);
        }

        [HttpPost]
        //[RequireSsl(Redirect = true)]
        public ActionResult ResetPassword(AccountModel model)
        {
            var message = string.Empty;
            if (ModelState.IsValid)
            {
                string username = Membership.GetUserNameByEmail(model.Email);

                if (!String.IsNullOrEmpty(username))
                {
                    // This is a helper function that sends an email with a token (an MD5).
                    var user = _accountService.GetUser(username);
                    user.PasswordAnswer = PasswordGenerator.GeneratePassword(7);
                    _accountService.EditUserEntity(user);
                    MvcCmsEmails.ResetPassword(user);
                    message = "A password reset email has been sent.  Please be sure to check that support@wepayonline.net is an allowed sender to your email.";
                }
                else
                {
                    message = String.Format("*** WARNING:  A user tried to retrieve their password but the email address used '{0}' does not exist in the database.", model.Email);
                }
            }

            ViewBag.Title = _sitename + " - " + "Reset Password";
            var viewModel = new AccountModel
            {
                Message = message,
                _Portal = _currentPortal
            };

            return View(viewModel);
        }

        public ActionResult Validate(string email, string token)
        {
            var user = _accountService.GetUserByEmail(email);

            if (PasswordResetToken.IsTokenValid(token, email, user.PasswordAnswer, DateTime.Now))
            {
                string username = Membership.GetUserNameByEmail(email);
                if (!String.IsNullOrEmpty(username))
                {
                    // Force password change by isapproved=false
                    user.IsApproved = false;
                    //remove the temp password answer so that the email link does not work going forward
                    user.PasswordAnswer = null;
                    _accountService.EditUser(user);

                    // Since it was a successful validation, authenticate the user.
                    FormsAuthentication.SetAuthCookie(username, false);

                    //they have already validated from email their identity
                    TempData["EMAILPASSWORDCHANGE"] = true;
                    Session["EPC_UserName"] = user.UserName;
                    Session["EPC_Guid"] = Guid.NewGuid();
                    return RedirectToAction("ChangePassword");
                }
            }
            var viewModel = new AccountModel
            {
                Message = "There was a problem with your password change validation link.  Please try again or contact " + _currentPortal.AdminEmail,
                _Portal = _currentPortal
            };
            return View(viewModel);
        }

        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.User.Identity is WindowsIdentity)
            {
                throw new InvalidOperationException("Windows authentication is not supported.");
            }
        }

        #endregion

        #region OpenId Methods

        [AcceptVerbs(HttpVerbs.Post | HttpVerbs.Get), ValidateInput(false)]
        public ActionResult OpenIdLogon(string returnUrl)
        {
            ViewData["resourcebody"] = "";
            var openid = new OpenIdRelyingParty();
            ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
            var response = openid.GetResponse();
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Login";
            if (returnUrl == null)
            {
                ViewData["referer"] = Session["returnUrl"];
            }
            else
            {
                ViewData["referer"] = returnUrl;
            }
            Session["returnUrl"] = returnUrl;
            if (response == null)
            {
                // Step 2 - Send the reques to the OpenId provider server
                Identifier id;

                if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                {
                    try
                    {
                        var req = openid.CreateRequest(id);

                        var fields = new ClaimsRequest();
                        fields.Email = DemandLevel.Require;
                        fields.FullName = DemandLevel.Require;
                        req.AddExtension(fields);

                        return req.RedirectingResponse.AsActionResult();
                    }
                    catch (ProtocolException ex)
                    {
                        // display error by showing original LogOn view
                        ViewData["message"] = "Unable to authenticate: " + ex.Message;
                        return View("Logon");
                    }
                }
                else
                {
                    // display error by showing original LogOn view
                    ViewData["message"] = "Invalid identifier";
                    return View("LogOn");
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        string identifier = response.ClaimedIdentifier;
                        var user = _accountService.GetUserByOpenId(identifier);
                        if (user == null)
                        {
                            //this is a existing user wishing to associate their
                            //account with an open id
                            Session["OpenId"] = identifier;
                            ViewData["message"] = "We found your OpenId, To associate it with your existing account enter your UserName and Password and from now on you will use OpenId to login.";

                            string host = StringUtils.ExtractString(response.FriendlyIdentifierForDisplay, ".", ".com");
                            ViewData["OpenId"] = "Unknown" + host;

                            return View("LogOn");
                        }
                        _formsAuth.SignIn(user.UserName, true);
                        if ((!String.IsNullOrEmpty(returnUrl)) && (!returnUrl.Contains("logon")))
                        {
                            return Redirect(returnUrl);
                        }
                        return RedirectToAction("Index", "Home");

                    case AuthenticationStatus.Canceled:
                        ViewData["message"] = "Canceled at provider";
                        return View("LogOn");
                    case AuthenticationStatus.Failed:
                        ViewData["message"] = response.Exception.Message;
                        return View("LogOn");
                }
            }
            return new EmptyResult();
        }

        [AcceptVerbs(HttpVerbs.Post | HttpVerbs.Get), ValidateInput(false)]
        public ActionResult OpenIdRegister(string returnUrl)
        {
            ViewData["resourcebody"] = "";
            var openid = new OpenIdRelyingParty();
            var response = openid.GetResponse();
            if (returnUrl == null)
            {
                ViewData["referer"] = Session["returnUrl"];
            }
            else
            {
                ViewData["referer"] = returnUrl;
            }
            Session["returnUrl"] = returnUrl;
            ViewData["Message"] = "";
            ViewData["AllowOpenIdRegistration"] = _currentPortal.AllowOpenIdRegistration;
            ViewData["OpenId"] = "";
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Register";
            if (response == null)
            {
                // Stage 2: user submitting Identifier
                Identifier id;
                if (Identifier.TryParse(Request.Form["openid_identifier"], out id))
                {
                    try
                    {
                        return openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
                    }
                    catch (ProtocolException ex)
                    {
                        ViewData["Message"] = ex.Message;
                        return View("Register");
                    }
                }
                else
                {
                    ViewData["Message"] = "Invalid identifier";
                    return View("Register");
                }
            }
            else
            {
                // Stage 3: OpenID Provider sending assertion response
                switch (response.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        string identifier = response.ClaimedIdentifier;
                        //see if there is a user with this OpenId
                        var user = _accountService.GetUserByOpenId(identifier);
                        if (user == null)
                        {
                            //they need to declare a UserName store the OpenId to associate with the new account.
                            Session["OpenId"] = identifier;
                            ViewData["message"] = "OpenId authentication was successfull.  Please enter a user name and email address.";
                            string host = StringUtils.ExtractString(response.FriendlyIdentifierForDisplay, ".", ".com");
                            ViewData["OpenId"] = "Unknown" + host;
                            return View("Register");
                        }
                        else
                        {
                            _formsAuth.SignIn(user.UserName, true);
                            if ((!String.IsNullOrEmpty(returnUrl)) && (!returnUrl.Contains("logon")))
                            {
                                return Redirect(returnUrl);
                            }
                            return RedirectToAction("Index", "Home");
                        }
                    case AuthenticationStatus.Canceled:
                        ViewData["Message"] = "Canceled at provider";
                        return View("Register");
                    case AuthenticationStatus.Failed:
                        ViewData["Message"] = response.Exception.Message;
                        return View("Register");
                }
            }
            return new EmptyResult();
        }

        #endregion

        #region AdminMethods

        [Authorize(Roles = "Admin")]
        public ActionResult ManageRoles(string id, string newRole)
        {
            if (!String.IsNullOrEmpty(id))
            {
                Roles.DeleteRole(id);
            }
            if (!String.IsNullOrEmpty(newRole))
            {
                Roles.CreateRole(newRole);
            }
            ViewData["TotalRoles"] = Roles.GetAllRoles().Count();
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Manage Roles";
            return View("ManageRoles");
        }

        [Authorize(Roles = "Admin")]
        public ActionResult AddRemoveUsersInRole(string id)
        {
            var role = _accountService.GetRole(id);
            var usersInRole = _accountService.ListUsersInRole(id);
            var usersNotInRole = _accountService.ListUsersNotInRole(id);

            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Add Remove Users In Role " + role.RoleName;
            var model = new AccountModel
            {
                _UsersNotInRole = usersNotInRole,
                _UsersInRole = usersInRole,
                _Role = role
            };
            return View(model);
        }

        [Authorize(Roles = "Admin")]
        public ActionResult ManageUsers(string id, string searchType, string searchInput)
        {
            ViewData["Message"] = "";
            if (!String.IsNullOrEmpty(id))
            {
                if (Membership.DeleteUser(id))
                {
                    Session["DeleteMessage"] = "The user was deleted.";
                    return RedirectToAction("manageusers", new { id = "" });
                }
                else
                {
                    Session["DeleteMessage"] = "The user could not be deleted.  Make sure all comments or other user items have been deleted first.";
                    return RedirectToAction("manageusers", new { id = "" });
                }
            }

            if (Session["DeleteMessage"] != null)
            {
                ViewData["Message"] = Session["DeleteMessage"];
                Session["DeleteMessage"] = null;
            }

            var searchOptionList = new List<SelectListItem>
                                       {
                                           new SelectListItem {Value = "UserName", Text = "UserName"},
                                           new SelectListItem {Value = "Email", Text = "Email"}
                                       };
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Manage Users";
            ViewData["searchOptionList"] = new SelectList(searchOptionList, "Value", "Text", searchType ?? "UserName");
            ViewData["searchInput"] = searchInput ?? string.Empty;
            ViewData["UsersOnlineNow"] = Membership.GetNumberOfUsersOnline().ToString();
            return View();
        }

        [Authorize(Roles = "Admin")]
        public ActionResult EditUser(string id, bool? approved, bool? islockedout)
        {
            //Is a list of all the user roles
            var removeRoleList = new ArrayList(Roles.GetAllRoles());
            bool isPostback = false;

            //We are requesting the form variables directly from the form
            bool bChecked = false;

            foreach (String key in Request.Form.Keys)
            {
                if (key.StartsWith("role."))
                {
                    String userRole = key.Substring(5, key.Length - 5);

                    //was the roles checkbox checked?
                    if (Request != null) bChecked = bool.Parse(Request.Form.GetValues(key)[0]);
                    if (bChecked)
                    {
                        //if the checkbox was checked
                        //add them to the role if they aren't in it
                        //take the role out of the list of roles to remove

                        //takes the role out of the list of roles to remove
                        removeRoleList.Remove(userRole);
                        //if the user isn't in the role adds them to it
                        if (!Roles.IsUserInRole(id, userRole))
                        {
                            Roles.AddUserToRole(id, userRole);
                        }
                    }
                }
                isPostback = true;
            }

            //If keys were present then this is assumed to be a postback event
            if (isPostback)
            {
                foreach (string removeRole in removeRoleList)
                {
                    //if user is in role remove them from it.
                    if (Roles.IsUserInRole(id, removeRole))
                    {
                        Roles.RemoveUserFromRole(id, removeRole);
                    }
                }
                User user = _accountService.GetUser(id);

                if (approved != null)
                {
                    user.IsApproved = (bool)approved;
                }
                else
                {
                    user.IsApproved = false;
                }
                user.IsLockedOut = islockedout ?? false;
                _accountService.EditUser(user);

                TempData["SuccessMessage"] = "User Information has been updated";
                ViewData["id"] = id;
                ViewData["roles"] = Roles.GetAllRoles();
                ViewData["membershipUser"] = Membership.GetUser(id);
                return View("EditUser");
            }
            ViewData["SiteName"] = _sitename;
            ViewData["PageTitle"] = "Edit User";
            ViewData["id"] = id;
            ViewData["roles"] = Roles.GetAllRoles();
            ViewData["membershipUser"] = Membership.GetUser(id);
            return View("EditUser");
        }

        #endregion

        #region Validation Methods

        private bool ValidateChangePassword(string newPassword, string confirmPassword)
        {
            if (newPassword == null || newPassword.Length < Membership.MinRequiredPasswordLength)
            {
                ModelState.AddModelError("newPassword",
                                         String.Format(CultureInfo.CurrentCulture,
                                                       "You must specify a new password of {0} or more characters.",
                                                       Membership.MinRequiredPasswordLength));
            }

            if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }

            return ModelState.IsValid;
        }


        private bool ValidateChangePassword(string currentPassword, string newPassword, string confirmPassword)
        {
            if (String.IsNullOrEmpty(currentPassword))
            {
                ModelState.AddModelError("currentPassword", "You must specify a current password.");
            }
            if (newPassword == null || newPassword.Length < Membership.MinRequiredPasswordLength)
            {
                ModelState.AddModelError("newPassword",
                                         String.Format(CultureInfo.CurrentCulture,
                                                       "You must specify a new password of {0} or more characters.",
                                                       Membership.MinRequiredPasswordLength));
            }

            if (!String.Equals(newPassword, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }

            return ModelState.IsValid;
        }

        private bool ValidateLogOn(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(password))
            {
                ModelState.AddModelError("password", "You must specify a password.");
            }
            if (!Membership.ValidateUser(userName, password))
            {
                var user = Membership.GetUser(userName);
                if (user == null)
                {
                    ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
                }
                else if (!user.IsApproved)
                {
                    //measures to see if the password was changed by an admin since their last login was before the password change
                    //so even though they are marked IsApproved=false they just need to change their password
                    var timeSpan = user.LastLoginDate - user.LastPasswordChangedDate;
                    if (timeSpan.Seconds < 0)
                    {
                        ModelState.AddModelError("ADMINPASSWORDCHANGE", "You must create a new password.");
                    }
                    else
                    {
                        ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
                    }
                }
                else
                {
                    ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
                }
            }
            else
            {
                var user = Membership.GetUser(userName);
                if (user == null)
                {
                    ModelState.AddModelError("_FORM", "The username or password provided is incorrect.");
                }
                else
                {
                    if (user.IsLockedOut) { user.UnlockUser(); }

                    //measures to see if the password was changed by an admin since their last login was before the password change
                    var timeSpan = user.LastLoginDate - user.LastPasswordChangedDate;
                    if (timeSpan.Seconds < 0)
                    {
                        user.IsApproved = false;
                        Membership.UpdateUser(user);
                        ModelState.AddModelError("ADMINPASSWORDCHANGE", "You must create a new password.");
                    }
                }
            }
            return ModelState.IsValid;
        }

        private bool ValidateRegistration(string userName, string email, string password, string confirmPassword)
        {
            if (String.IsNullOrEmpty(userName))
            {
                ModelState.AddModelError("username", "You must specify a username.");
            }
            if (String.IsNullOrEmpty(email))
            {
                ModelState.AddModelError("email", "You must specify an email address.");
            }
            if (password == null || password.Length < Membership.MinRequiredPasswordLength)
            {
                ModelState.AddModelError("password",
                                         String.Format(CultureInfo.CurrentCulture,
                                                       "You must specify a password of {0} or more characters.",
                                                       Membership.MinRequiredPasswordLength));
            }
            if (!String.Equals(password, confirmPassword, StringComparison.Ordinal))
            {
                ModelState.AddModelError("_FORM", "The new password and confirmation password do not match.");
            }
            return ModelState.IsValid;
        }

        private static string ErrorCodeToString(MembershipCreateStatus createStatus)
        {
            // See http://msdn.microsoft.com/en-us/library/system.web.security.membershipcreatestatus.aspx for
            // a full list of status codes.
            switch (createStatus)
            {
                case MembershipCreateStatus.DuplicateUserName:
                    return "UserName already exists. Please enter a different user name.";

                case MembershipCreateStatus.DuplicateEmail:
                    return "A username for that e-mail address already exists. Please enter a different e-mail address.";

                case MembershipCreateStatus.InvalidPassword:
                    return "The password provided is invalid. Please enter a valid password value.";

                case MembershipCreateStatus.InvalidEmail:
                    return "The e-mail address provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidAnswer:
                    return "The password retrieval answer provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidQuestion:
                    return "The password retrieval question provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.InvalidUserName:
                    return "The user name provided is invalid. Please check the value and try again.";

                case MembershipCreateStatus.ProviderError:
                    return
                        "The authentication provider returned an error. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                case MembershipCreateStatus.UserRejected:
                    return
                        "The user creation request has been canceled. Please verify your entry and try again. If the problem persists, please contact your system administrator.";

                default:
                    return
                        "An unknown error occurred. Please verify your entry and try again. If the problem persists, please contact your system administrator.";
            }
        }

        #endregion
    }

}